package com.cory.boot.support.mybatis.interceptor;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.List;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Joiner;

/**
 * 所有页面统计
 * @author xiongcong
 * @date 2023-02-06
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Slf4j
public class AllPageTotalHelper implements Interceptor {
    
    protected static final ThreadLocal<String[]> LOCAL_SELECT = new ThreadLocal<String[]>();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        String[] columns = LOCAL_SELECT.get();
        if (columns == null) {
            return invocation.proceed();
        }
        
        try {
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            //通过MetaObject优雅访问对象的属性，这里是访问statementHandler的属性;：MetaObject是Mybatis提供的一个用于方便、
            //优雅访问对象属性的对象，通过它可以简化代码、不需要try/catch各种reflect异常，同时它支持对JavaBean、Collection、Map三种类型对象的操作。
//            MetaObject metaObject = MetaObject.forObject(statementHandler,
//                    SystemMetaObject.DEFAULT_OBJECT_FACTORY,
//                    SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
//                    new DefaultReflectorFactory());
            //先拦截到RoutingStatementHandler，里面有个StatementHandler类型的delegate变量，其实现类是BaseStatementHandler，然后就到BaseStatementHandler的成员变量mappedStatement
//            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
            BoundSql boundSql = statementHandler.getBoundSql();
            Field filed = boundSql.getClass().getDeclaredField("sql");
            filed.setAccessible(true);
            
            String replace = boundSql.getSql();
            replace = replace.replace("FROM", "from").replace("ORDER BY", "order by");
            
//            System.out.println("sql：" + replace);
            replace = replace.substring(replace.indexOf("from"));
            
            
            if (replace.lastIndexOf("order by") > 0) {
                replace = replace.substring(0, replace.lastIndexOf("order by"));
            }
            
            List<String> sums = Lists.newArrayList();
            for (String column : columns) {
                if (column.indexOf("sum") >= 0) {
                    sums.add(column);
                    continue;
                }
                
                if (column.indexOf("as") >= 0) {
                    sums.add("sum(" + column.split("as")[0] + ") as " + column.split("as")[1]);
                } else {
                    if (column.indexOf(".") >= 0) {
                        sums.add("sum(" + column + ") as " + column.split("\\.")[1]);
                    } else {
                        sums.add("sum(" + column + ") as " + column);
                    }
                }
            }
            replace = "select " + Joiner.on(",").join(sums) + " " + replace;
//            System.out.println("sql2：" + replace);
            
            filed.set(boundSql, replace);
        } catch(Exception e) {
            log.error("", e);
        } finally {
            LOCAL_SELECT.remove();
        }
        return invocation.proceed();
    }
    
    @Override
    public Object plugin(Object target) {
        Object wrap = Plugin.wrap(target, this);
        return wrap;
    }
    
    @Override
    public void setProperties(Properties arg0) {}
    
    public static void start(String... columns) {
        LOCAL_SELECT.set(columns);
    }
}
